#include <buola/scene/controllers/ccameracontroller.h>

#include <buola/gui/cwindow.h>
#include <buola/scene/ccamera.h>

namespace buola { namespace scene {

CCameraController::CCameraController(PCamera pCamera)
    :   mCamera(pCamera)
    ,   mDragging(false)
{
}
    
void CCameraController::OnButtonDown(const gui::CMouseEvent &pE)
{
    if(pE.mButton==gui::EMouseButton::LEFT)
    {
        mDragging=true;
        mDragFrom=mCamera->GetFrom();
        mDragUp=mCamera->GetUp();
        mDragPoint=pE.mPoint;
    }
//    else if(pE.mButton==gui::EMouseButton::RIGHT)
//    {
//        CalcClosestPoint(pE.mPoint);
//    }
}

void CCameraController::OnButtonUp(const gui::CMouseEvent &pE)
{
    if(pE.mButton==gui::EMouseButton::LEFT)
    {
        mDragging=false;
    }
}

void CCameraController::OnMouseMove(const gui::CMouseEvent &pE)
{
    if(mDragging)
    {
        CPoint_d lDiff=pE.mPoint-mDragPoint;
        mat::CVec3d lAt=mCamera->GetAt();
        if(norm(lDiff)==0) return;
        mat::CVec3d lPerp=cross(mDragUp,mDragFrom-lAt);
        lPerp=lPerp/norm(lPerp);
        mat::CQuat_d lQuat=mat::CQuat_d(0.02*norm(lDiff),(-lDiff.x*mDragUp-lDiff.y*lPerp)/norm(lDiff));
        mat::CMat34d lRot=mat::rotation_3d_around(lQuat,lAt);
        
        mCamera->LookAt(lAt,lRot*mDragFrom,lQuat*mDragUp);
        pE.mTarget->Refresh();
    }
}

void CCameraController::OnMouseWheel(const gui::CMouseEvent &pE)
{
    if(pE.mScrollY!=0.0)
    {
        mat::CVec3d lAt=mCamera->GetAt();
        mat::CVec3d lFrom=mCamera->GetFrom();
        mat::CVec3d lToward=lAt-lFrom;
        mCamera->LookAt(lAt,lAt-lToward*pow(1.05,pE.mScrollY),mCamera->GetUp());
        pE.mTarget->Refresh();
    }
}

/*namespace scene*/ } /*namespace buola*/ }
